package com.zjpavt.client.command.kcommand;

import com.zjpavt.client.hal.LoopManager;
import com.zjpavt.client.job.JobRunner;
import com.zjpavt.client.util.Consts;
import com.zjpavt.client.util.LoggerUtil;
import com.zjpavt.client.util.PropertiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.time.Instant;
import java.util.regex.Pattern;

/**
 * 用于K指令管理的类
 *
 * @author: gxy
 */
public class KCommandManager {
    private static final Logger log = LoggerFactory.getLogger(KCommandManager.class);
    /**
     * 单例管理类
     */
    private static final KCommandManager K_COMMAND_MANAGER = new KCommandManager();

    private static final Pattern K_PATTERN = Pattern.compile("^[0-1]+$");
    /**
     * 用于存贮到时长k指令数据作为共享资源
     */
    private final KCommandBean kCommandBeanWithTime;
    /**
     * 用于存贮到不带时长k指令数据作为共享资源
     */
    private final KCommandBean kCommandBean;

    private static final String DEFAULT_COMMAND = LoopManager.getInstance().getAllClosedCommand();

    private KCommandManager() {
        kCommandBeanWithTime = new KCommandBean();
        kCommandBean = new KCommandBean();
        initKCommandData();
    }

    /**
     * 初始化kCommandBeanWithTime与kCommandBean
     */
    private void initKCommandData() {
        String command;
        long endTime;
        try {
            command = PropertiesUtil.getPropertiesDefault(Consts.KEY_K_COMMAND_WITH_TIME);
            endTime = Long.parseLong(PropertiesUtil.getPropertiesDefault(Consts.KEY_K_COMMAND_WT_END_TIME));
        } catch (IOException | NumberFormatException e) {
            log.error(LoggerUtil.convertException2String(e));
            endTime = 0;
            command = DEFAULT_COMMAND;
        }
        synchronized (kCommandBeanWithTime) {
            kCommandBeanWithTime.setCommand(command);
            kCommandBeanWithTime.setEndTime(endTime);
        }
        try {
            command = PropertiesUtil.getPropertiesDefault(Consts.KEY_K_COMMAND_NOT_WITH_TIME);
            endTime = Long.parseLong(PropertiesUtil.getPropertiesDefault(Consts.KEY_K_COMMAND_NWT_END_TIME));
        } catch (IOException | NumberFormatException e) {
            log.error(LoggerUtil.convertException2String(e));
            endTime = 0;
            command = DEFAULT_COMMAND;
        }
        synchronized (kCommandBean) {
            kCommandBean.setCommand(command);
            kCommandBean.setEndTime(endTime);
        }
    }

    public KCommandBean getKCommandBean() {
        synchronized (kCommandBean) {
            return new KCommandBean(kCommandBean);
        }
    }

    public KCommandBean getKCommandBeanWithTime() {
        synchronized (kCommandBeanWithTime) {
            return new KCommandBean(kCommandBeanWithTime);
        }
    }

    /**
     * @return 是否清除带时长的k指令成功
     */
    public boolean clearKCommandWithTime() {
        boolean result = true;
        try {
            storeKCommandWithTime(DEFAULT_COMMAND, 0);
        } catch (IOException e) {
            log.error(LoggerUtil.convertException2String(e));
            result = false;
        }
        return result;
    }

    /**
     * 用于存储带时长的k指令
     *
     * @param command k指令
     * @param endTime 结束时间
     * @return 是否保存成功
     */
    public boolean saveKCommandWithTime(String command, Long endTime) {
        if (command == null || endTime == null) {
            return false;
        }
        boolean result = false;
        if (K_PATTERN.matcher(command).matches()) {
            try {
                storeKCommandWithTime(command, endTime + Instant.now().toEpochMilli());
            } catch (IOException e) {
                log.error(LoggerUtil.convertException2String(e));
            }
            result = true;
        }
        return result;
    }

    /**
     * 用于存储不带时长的k指令
     *
     * @param command k指令
     * @return 是否保存成功
     */
    public boolean saveKCommand(String command) {
        if (command == null) {
            return false;
        }
        boolean result = false;
        if (K_PATTERN.matcher(command).matches()) {
            try {
                storeKCommand(command, Instant.now().toEpochMilli() + Consts.K_COMMAND_TIMEOUT);
            } catch (IOException e) {
                log.error(LoggerUtil.convertException2String(e));
            }
            result = true;
        }
        return result;
    }

    /**
     * @return 是否清除不带时长的k指令成功
     */
    public boolean clearKCommand() {
        boolean result = true;
        try {
            storeKCommand(DEFAULT_COMMAND, 0);
        } catch (IOException e) {
            log.error(LoggerUtil.convertException2String(e));
            result = false;
        }
        return result;
    }

    /**
     * 用于存储带时长的k指令
     *
     * @param command k指令
     * @param endTime 结束时间
     * @throws IOException 存储错误抛出异常
     */
    private void storeKCommandWithTime(String command, long endTime) throws IOException {
        synchronized (kCommandBeanWithTime) {
            if (command == null || endTime < 0) {
                return;
            }
            PropertiesUtil.setPropertyOrReplaceDefault(Consts.KEY_K_COMMAND_WITH_TIME, command);
            PropertiesUtil.setPropertyOrReplaceDefault(Consts.KEY_K_COMMAND_WT_END_TIME, String.valueOf(endTime));
            kCommandBeanWithTime.setCommand(command);
            kCommandBeanWithTime.setEndTime(endTime);
            if (endTime != 0) {
                JobRunner.getInstance().switchToKCommandWithTime();
            }
        }
    }

    /**
     * 用于存储不带时长的k指令 与之
     *不在具备执行功能 因为开机的时候需要stroe 不需要run
     * @param command k指令
     * @param endTime 结束时间
     * @throws IOException 存储错误抛出异常
     */
    private void storeKCommand(String command, long endTime) throws IOException {
        synchronized (kCommandBean) {
            if (command == null || endTime < 0) {
                return;
            }
            PropertiesUtil.setPropertyOrReplaceDefault(Consts.KEY_K_COMMAND_NOT_WITH_TIME, command);
            PropertiesUtil.setPropertyOrReplaceDefault(Consts.KEY_K_COMMAND_NWT_END_TIME, String.valueOf(endTime));
            kCommandBean.setCommand(command);
            kCommandBean.setEndTime(endTime);
            if (endTime != 0) {
                clearKCommandWithTime();
                JobRunner.getInstance().switchToKCommandWithoutTime();
            }
        }
    }

    /**
     * @return 获取单例的KCommandManager实例
     */
    public static KCommandManager getInstance() {
        return K_COMMAND_MANAGER;
    }

    public class KCommandBean {
        /**
         * K指令执行命令
         */
        private String command;
        /**
         * 当前k指令执行的结束时间
         */
        private long endTime;

        private KCommandBean() {
        }

        private KCommandBean(KCommandBean bean) {
            this.command = bean.command;
            this.endTime = bean.endTime;
        }

        public String getCommand() {
            return command;
        }

        public void setCommand(String command) {
            this.command = command;
        }

        public long getEndTime() {
            return endTime;
        }

        public void setEndTime(long endTime) {
            this.endTime = endTime;
        }
    }
}
